package praktikumid.w10.p2;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

/**
 * Panel for drawing.
 * @author Ago
 *
 */
public class DrawPanel extends JPanel {
	/**
	 * All the shapes we need to draw.
	 */
	private List<Shape> shapes = new ArrayList<Shape>();
	
	/**
	 * Highlighted shape.
	 */
	Shape selectedShape = null;
	
	/**
	 * Listener for mouse clicks, mouse movement (drag) 
	 * and keyboard clicks. Note the usage of MouseAdapter.
	 * MouseAdapter implements MouseListener and 
	 * MouseMotionListener. Every method is implemented
	 * with the empty block. So, here we don't have to 
	 * implement all the necessary methods. Instead we
	 * override methods, which we need to use.
	 * @author Ago
	 *
	 */
	class DrawListener extends MouseAdapter implements KeyListener {
		@Override
		public void mouseDragged(MouseEvent e) {
			// if mouse is dragged (button is down and mouse moves).
			//System.out.println(e.getModifiers() + ", " + MouseEvent.BUTTON3);
			// & - bitwise AND
			// works like this
			// given 2 binary number
			// a = 01100
			// b = 01001
			// a & b = 01000 (only bits where originally both arguments had 1
			// are set to 1).
			if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) == MouseEvent.BUTTON3_MASK) {
				// if we use third button, lets try to select
				// a shape closest to the cursor.
				selectShape(e.getPoint());
			} else {
				// otherwise delegate drag to the last shape
				// in the shapes list.
				getLastShape().drag(e);
			}
			// let's repaint - redraw everything
			repaint();
		}
		
		@Override
		public void mouseReleased(MouseEvent e) {
			// when mouse button is released
			if (e.getButton() == MouseEvent.BUTTON3) {
				// we could release the selected shape
				// but then again we couldn't
				// move the selected shape.
				//selectedShape = null;
				repaint();
			} else {
				// delegate release to the last shape
				getLastShape().release(e);

			}
			// we don't need to repaint here
			// has nothing usually changes
			// when releasing the button
			// (although it can be changed,
			// depending on the shapes we can draw).
			//repaint();
		}
		@Override
		public void mouseClicked(MouseEvent e) {
			// when mouse is clicked
			// this event is called AFTER mouseReleased().
			getLastShape().click(e);
			repaint();
		}

		@Override
		public void keyPressed(KeyEvent e) {
			// when keyboard key is pressed
			System.out.println("pressed" + e.getKeyCode());
			if (e.getKeyCode() == KeyEvent.VK_LEFT) {
				if (selectedShape != null) {
					// let's move the shape to the left
					selectedShape.move(-10, 0);
					repaint();
				}
			}
			
		}

		@Override
		public void keyReleased(KeyEvent e) {
			// here we needed to implement those methods
		}

		@Override
		public void keyTyped(KeyEvent e) {
			
		}
	}
	
	/**
	 * Constructor. 
	 */
	public DrawPanel() {
		setBackground(Color.WHITE);
		// just adds one shape to the list
		// to test things out.
		shapes.add(new Oval());
		
		// By default, JPanel does is not focused.
		// In order to listen key events (key pressed etc)
		// we need to get focus. Therefore, we first
		// need to make panel focusable.
		setFocusable(true);
		// after that, we need to request focus for
		// the panel.
		requestFocus();
		
		// we use the same listener for
		// three different cases
		DrawListener l = new DrawListener();
		addMouseListener(l);
		addMouseMotionListener(l);
		addKeyListener(l);
	}
	
	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		// here we just loop every shape
		// and call their paint method
		for (Shape s : shapes) {
			s.paintComponent(g);
		}
	}
	/**
	 * Returns the last shape. If the
	 * last shape is finished, we will create
	 * a new shape and return it.
	 * 
	 * In the class we had 2 methods,
	 * but as we ended up using only one of those,
	 * I removed the other way to call getLastShape().
	 * @return Last (active) shape we are drawing
	 */
	public Shape getLastShape() {
		if (true) {
			if (shapes.size() == 0 
					|| shapes.get(shapes.size() - 1).isFinished()) {
				// we need to create a new shape
				// if there are no shapes
				// or the last one is finished
				
				// we could use a status,
				// which would specify which
				// shape to create,
				// and status could be changed
				// with a button or a key etc.
				
				//shapes.add(new Oval());
				shapes.add(new ClosedShape());
			}
		}
		return shapes.get(shapes.size() - 1);
	}
	
	/**
	 * Selects the closest shape for the given point.
	 * @param p Point to find the closest shape to.
	 */
	public void selectShape(Point p) {
		int minDistance = Integer.MAX_VALUE;
		Shape closestShape = null;
		for (Shape s : shapes) {
			// let's find the closest ont
			int d = s.getDistance(p);
			if (d < minDistance) {
				minDistance = d;
				closestShape = s;
			}
		}
		
		// let's color the shapes
		for (Shape s : shapes) {
			if (closestShape == s) {
				s.highlight();
			} else {
				s.unHighlight();
			}
		}
		// let's have a reference to the selected shape
		selectedShape = closestShape;
	}
}
